package com.css.common.core.utils.xml;


import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.io.StringWriter;

public class JaxbUtils {

    private static final String DEFAULT_ENCODING = "UTF-8";

    /**
     * JavaBean转换成xml
     * 默认编码UTF-8
     *
     * @param obj obj
     * @return str
     */
    public static String convertToXml(Object obj) throws JAXBException {
        return convertToXml(obj, DEFAULT_ENCODING, false,false);
    }
    /**
     * JavaBean转换成xml
     * 默认编码UTF-8
     *
     * @param obj obj
     * @return str
     */
    public static String convertToXmlFormat(Object obj) throws JAXBException {
        return convertToXml(obj, DEFAULT_ENCODING, false,true);
    }

    /**
     * 转xml不带头信息
     *
     * @param obj obj
     * @return xml
     * @throws JAXBException err
     */
    public static String convertToXmlWitHOutHead(Object obj) throws JAXBException {
        return convertToXml(obj, DEFAULT_ENCODING, true,false);
    }

    /**
     * JavaBean转换成xml
     *
     * @param obj      OBJ
     * @param encoding CHARSET
     * @return XMLSTR
     */
    public static String convertToXml(Object obj, String encoding, boolean noHead,boolean format) throws JAXBException {
        String result = null;
        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();
        //xml格式化
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, format);
        //字符集
        marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, noHead);
        StringWriter writer = new StringWriter();
        marshaller.marshal(obj, writer);
        result = writer.toString();

        return result;
    }

    /**
     * 生成包含cdata的xml
     *
     * @param clazz class
     * @param obj   obj
     * @return xml
     * @throws JAXBException      err
     * @throws XMLStreamException err2
     */
    public static String convertToXmlWithCDATA(Class clazz, Object obj) throws JAXBException, XMLStreamException, TransformerException {
        return convertToXmlWithCDATA(clazz, obj, DEFAULT_ENCODING, false);
    }

    /**
     * 生成包含cdata的xml不带xml头
     *
     * @param clazz class
     * @param obj   obj
     * @return xml
     * @throws JAXBException      err
     * @throws XMLStreamException err2
     */
    public static String convertToXmlWithCDATAWithOutHead(Class clazz, Object obj) throws JAXBException, XMLStreamException, TransformerException {
        return convertToXmlWithCDATA(clazz, obj, DEFAULT_ENCODING, true);
    }

    /**
     * 生成包含cdata的xml
     *
     * @param clazz    class
     * @param obj      obj
     * @param encoding encoding
     * @return xml
     * @throws JAXBException      err
     * @throws XMLStreamException err2
     */
    public static String convertToXmlWithCDATA(Class clazz, Object obj, String encoding, boolean noHead) throws JAXBException, XMLStreamException, TransformerException {

        JAXBContext context = JAXBContext.newInstance(clazz);
        ByteArrayOutputStream op = new ByteArrayOutputStream();

        XMLOutputFactory xof = XMLOutputFactory.newInstance();
        XMLStreamWriter streamWriter = xof.createXMLStreamWriter(op);
        CDataXMLStreamWriter cdataStreamWriter = null;
        try {
            cdataStreamWriter = new CDataXMLStreamWriter(streamWriter);
            Marshaller mar = context.createMarshaller();
            mar.setProperty(Marshaller.JAXB_ENCODING, encoding);
            //去掉生成xml的默认报文头
            mar.setProperty(Marshaller.JAXB_FRAGMENT, noHead);

            mar.marshal(obj, cdataStreamWriter);
            cdataStreamWriter.flush();
        } finally {
            if (null != cdataStreamWriter) {
                cdataStreamWriter.close();
            }
        }
        return op.toString();
    }

    /**
     * 格式化xml报文
     * @param xml xml
     * @return formatxml
     * @throws TransformerException err
     */
    public static String indentFormat(String xml) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
        StringWriter formattedStringWriter = new StringWriter();
        transformer.transform(new StreamSource(new StringReader(xml)),
                new StreamResult(formattedStringWriter));
        return formattedStringWriter.toString();
    }

    /**
     * xml转换成JavaBean
     *
     * @param xml
     * @param c
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T converyToJavaBean(String xml, Class<T> c) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(c);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        T t = (T) unmarshaller.unmarshal(new StringReader(xml));
        return t;
    }

}

